package polimi.sc.expoquest.storage.datasources;

import java.util.ArrayList;
import java.util.Collection;

import polimi.sc.expoquest.storage.DBContract;
import polimi.sc.expoquest.storage.DBHelper;
import polimi.sc.expoquest.storage.model.GameOption;
import polimi.sc.expoquest.storage.model.SingleGame;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

/**
 * This class is in charge of managing all the database
 * operations related to the SINGLE GAME TABLE, using the 
 * database helper, which does the direct calls to the 
 * database
 * @author Monica Lozano
 *
 */
public class SingleGameDataSource {
	//------------------
	//ATTRIBUTES
	//------------------
	/**
	 * The object that represents the database
	 */
	private SQLiteDatabase db;
	/**
	 * The database helper for accessing the database 
	 */
	private DBHelper dbHelper;
	
	//----------------
	// CONSTRUCTOR
	//----------------
	public SingleGameDataSource(Context ctx)
	{
		//1. We create the DB helper
		dbHelper = new DBHelper(ctx);
	}
	
	//------------------
	//METHODS
	//------------------
	//database connection
	/**
	 * Opens the database such that we can used it for reading and writing
	 */
	public void open(){
		/* 
		 * TODO put this call in a asynchronous task, such that if it takes more than
		 * few seconds our application wont colapse.
		 */
		dbHelper.open();
		db = dbHelper.getWritableDatabase();
	}
	/**
	 * Close the database connection
	 */
	public void close()
	{
		dbHelper.close();
	}
	
	//Database operations
	/**
	 * @param type: type of game: SingleGame.TYPE_TRIVIA, SingleGame.TYPE_COMMENT, SingleGame.TYPE_CAMERA
	 * @return the single games of the given type, the remaining data related to the type should managed in the logic
	 * of the class that is using this datasource
	 */
	public Collection<SingleGame> getSingleGameByType(int type)
	{
		//1. Doing the consult
		Cursor cursor = db.query(DBContract.SingleGame.TABLE_NAME,DBContract.SingleGame.ALL_COLUMNS,
										DBContract.SingleGame.CLM_NAME_TYPE +"="+ type,null,null,null,null);
		//2. We create the list from the results of the query
		Collection<SingleGame> sgs = buildCollectionFromCursor(cursor);
		return sgs;
	}
	/**
	 * @param singleGameID
	 * @return Returns the set of options of the single game , ONLY the ID is given
	 * TODO improve it with a join query..HOW TO DO IT? on this framework?
	 */
	public Collection<GameOption> getOptionsForSingleGame(int singleGameID)
	{
		//1. Doing the consult
		Cursor cursor = db.query(DBContract.GameOption.TABLE_NAME,DBContract.GameOption.ALL_COLUMNS,
										DBContract.GameOption.CLM_NAME_GAME_ID +"="+ singleGameID,null,null,null,null);
		//2. We create the list from the results of the query. Options without the text
		Collection<GameOption> options = buildOptionsFromCursor(cursor);
		addOptionsText(options);
		return options;
	}
	/**
	 * Adds the missing text that we retrieve fromt the option table
	 * @param options
	 * TODO delete this method and retrieve everything in just one query on the main method
	 */
	
	private void addOptionsText(Collection<GameOption> options) {
		
		for (GameOption opt : options) {
			//3. Retrieving the option text from the database
			Cursor cursor = db.query(DBContract.Option.TABLE_NAME,DBContract.Option.ALL_COLUMNS,
					DBContract.Option._ID +"="+ opt.getId(),null,null,null,null);
			//3.1. Move the cursor to recent inserted row
			cursor.moveToFirst();
			//3.2. Creating the game option object
			int optionTxtIndex = cursor.getColumnIndex(DBContract.Option.CLM_NAME_TEXT);
			String optionText = cursor.getString(optionTxtIndex);
			opt.setOption(optionText);
			//3.3 Closing the cursor
			cursor.close();
		}
		
	}

	/**
	 * Builds the collection of options that are pointed by the cursor
	 * @param cursor
	 * @return Builds a collection of singe game objects based on the results pointed by the given cursor
	 */
	private Collection<GameOption> buildOptionsFromCursor(Cursor cursor)
	{
		Collection<GameOption> options = new ArrayList<GameOption>();
		cursor.moveToFirst();
		while(!cursor.isAfterLast())
		{
			GameOption option = cursorToGameOption(cursor);
			options.add(option);
			cursor.moveToNext();
		}
		cursor.close();
		return options;
	}
	
	/**
	 * @param cursor
	 * @return Builds a collection of singe game objects based on the results pointed by the given cursor
	 */
	private Collection<SingleGame> buildCollectionFromCursor(Cursor cursor)
	{
		Collection<SingleGame> sgs = new ArrayList<SingleGame>();
		cursor.moveToFirst();
		while(!cursor.isAfterLast())
		{
			SingleGame sg = cursorToSingleGame(cursor);
			sgs.add(sg);
			cursor.moveToNext();
		}
		cursor.close();
		return sgs;
	}
	
	/**
	 * Creates the single game object from the data in the current
	 * row of the cursor.
	 * @param cursor
	 * @return A single game structure with the basic data: the description, pic uri, type and max points
	 */
	private SingleGame cursorToSingleGame(Cursor cursor)
	{
		SingleGame sg = new SingleGame();
		//1. We obtain the columns indexes based on their names
		int idColIndex = cursor.getColumnIndex(DBContract.SingleGame._ID);
		int descColIndex = cursor.getColumnIndex(DBContract.SingleGame.CLM_NAME_DESCRIPTION);
		int typeColIndex = cursor.getColumnIndex(DBContract.SingleGame.CLM_NAME_TYPE);
		int maxPColIndex = cursor.getColumnIndex(DBContract.SingleGame.CLM_NAME_MAXPOINTS);
		int pictUColIndex = cursor.getColumnIndex(DBContract.SingleGame.CLM_NAME_PIC_URI);
		//2.We obtain the data from the row based on the index
		int id =  cursor.getInt(idColIndex);
		String description = cursor.getString(descColIndex);
		String picURI = cursor.getString(pictUColIndex);
		int type = cursor.getInt(typeColIndex);
		int maxPoints = cursor.getInt(maxPColIndex);
		//3.We save the data in the object
		sg.setId(id);
		sg.setDescription(description);
		sg.setMaxPoints(maxPoints);
		sg.setPicURI(picURI);
		sg.setType(type);
		return sg;
	}
	
	/**
	 * Creates the option object from the data in the current
	 * row of the cursor.
	 * @param cursor
	 * @return A game option structure with the basic data
	 */
	private GameOption cursorToGameOption(Cursor cursor)
	{
		GameOption option = new GameOption();
		//1. We obtain the columns indexes based on their names
		int oiColIndex = cursor.getColumnIndex(DBContract.GameOption.CLM_NAME_OPTION_ID);
		//2.We obtain the data from the row based on the index
		int optionID = cursor.getInt(oiColIndex);
		//3.We save the data in the object
		option.setId(optionID);
		return option;
	}
}
